<?php

namespace app\common\logic;

use app\common\configs\CommonData;
use app\common\model\commonModel;
use app\common\model\trCache;
use app\common\model\trDriver;
use app\common\model\trBusesLine;
use app\common\model\trOrder;
use app\common\model\trSystemSet;
use app\common\model\trUser;
use app\common\util\ErrorCode;
use app\common\util\Tools;
use app\common\util\WxPay;
use think\Db;

/**
 * Class orderLogic
 * @package Common\Logic
 */
class OrderLogic
{
    // 订单的定时任务
    public static function cancelOrderJobs($orderSn, $data = []){
        $cancelTime = trSystemSet::getValue("orderCancelTime");
        $cancelTime = !empty($cancelTime) ? 60 * $cancelTime : 1800; // 订单取消时长
        if(empty($data)){
            $orderModel = new trOrder();
            $data = $orderModel->getFields("order_sn,user_id", ["order_sn" => $orderSn]);
        }
        if(config("cache.type") == 'redis') { // redis
            $redisObject = new \Redis();
            $redisObject->connect(config("cache.host"), config("cache.port"), config("cache.timeout"));
            if (!empty(config("cache.password"))) {
                $redisObject->auth(config("cache.password"));
            }
            $redisObject->select(1); // 系统默认是用0数据库，那定时任务就用1数据库
            $redisObject->zAdd('orderCancelData', time() + $cancelTime, json_encode($data)); // cancel代表取消
            $redisObject->zAdd('orderNoPayData', time() + ceil($cancelTime/2), json_encode($data)); // 通知未付款
        }else{
            commonModel::toAdd(cronJobTable, ["key" => "orderCancelData", "value" => json_encode($data), "time" => time() + $cancelTime]);
            commonModel::toAdd(cronJobTable, ["key" => "orderNoPayData", "value" => json_encode($data), "time" => time() + ceil($cancelTime/2)]);
        }
    }

    public function startCancelOrderJobs(){
        if(config("cache.type") == 'redis') { // redis
            $redisObject = new \Redis();
            $redisObject->connect(config("cache.host"), config("cache.port"), config("cache.timeout"));
            if (!empty(config("cache.password"))) {
                $redisObject->auth(config("cache.password"));
            }
            $redisObject->select(1); // 系统默认是用0数据库，那定时任务就用1数据库
            $jobs = $redisObject->zRangeByScore("orderCancelData", '-inf', time());
            if(!empty($jobs)){
                foreach ($jobs as $member){
                    $item = json_decode($member, true);
                    $this->cancelOrder($item["orderSn"], $item["userId"], "系统自动取消", true);
                    $redisObject->zDelete("orderCancelData", $member);
                }
            }
            $jobs = $redisObject->zRangeByScore("orderNoPayData", '-inf', time());
            if(!empty($jobs)){ // 通知未支付
                $model = new trOrder();
                $userModel = new trUser();
                foreach ($jobs as $member){
                    $item = json_decode($member, true);
                    $orderData = $model->getFields("status,reserve_time,total_money,pay_money,address_from,address_to,mall_id", ["order_sn" => $item["orderSn"], "status" => 1]);
                    if(!empty($orderData)) {
                        if(empty($userData[$item["userId"]])){
                            $userData[$item["userId"]] = $userModel->getFields("openid,nickname", ["id" => $item["userId"]]);
                        }
                        if(empty($userData[$item["userId"]])){
                            continue;
                        }
                        $orderData["orderSn"] = $item["orderSn"];
                        $orderData["userName"] = $userData[$item["userId"]]["nickname"];
                        request()->mallData = ["id" => $orderData["mallId"]]; // 重置商城ID
                        WxAppLogic::sendNoPayTpl($item["userId"], $userData[$item["userId"]]["openid"], $orderData);
                    }
                    $redisObject->zDelete("orderNoPayData", $member);
                }
            }
        }else{
            $delete = [];
            $jobs = commonModel::getFields(cronJobTable, "id,value", [["key", "=", "orderCancelData"], ["time", "<=", time()]], false, false);
            if(!empty($jobs)){
                foreach ($jobs as $item){
                    $value = json_decode($item["value"], true);
                    $this->cancelOrder($value["orderSn"], $value["userId"], "系统自动取消", true);
                    $delete[] = $item["id"];
                }
            }
            $jobs = commonModel::getFields(cronJobTable, "id,value", [["key", "=", "orderNoPayData"], ["time", "<=", time()]], false, false);
            if(!empty($jobs)){ // 通知未支付
                $model = new trOrder();
                $userModel = new trUser();
                foreach ($jobs as $item){
                    $value = json_decode($item["value"], true);
                    $orderData = $model->getFields("status,reserve_time,total_money,pay_money,address_from,address_to,mall_id", ["order_sn" => $value["orderSn"], "status" => 1]);
                    if(!empty($orderData)) {
                        if(empty($userData[$value["userId"]])){
                            $userData[$value["userId"]] = $userModel->getFields("openid,nickname", ["id" => $value["userId"]]);
                        }
                        if(empty($userData[$value["userId"]])){
                            continue;
                        }
                        $orderData["orderSn"] = $value["orderSn"];
                        $orderData["userName"] = $userData[$value["userId"]]["nickname"];
                        request()->mallData = ["id" => $orderData["mallId"]]; // 重置商城ID
                        WxAppLogic::sendNoPayTpl($value["userId"], $userData[$value["userId"]]["openid"], $orderData);
                    }
                    $delete[] = $item["id"];
                }
            }
            if(!empty($delete)){
                commonModel::delById(cronJobTable, $delete);
            }
        }
        request()->mallData = ["id" => 0]; // 重置商城ID
        trCache::saveCache(["key" => CommonData::CANCEL_ORDER_JAVASCRIPT, "value" => [
            "name" => CommonData::$javascriptList[CommonData::CANCEL_ORDER_JAVASCRIPT], "aliasName" => CommonData::CANCEL_ORDER_JAVASCRIPT,
            'execTime' => date("Y-m-d H:i:s")
        ]]);
    }

    // 定时处理订单即将到期
    public function orderExpireJobs(){
        request()->mallData = ["id" => 0]; // 重置商城ID
        $cacheData = trCache::getValue("value", ["key" => "orderExpireJobs"], false);
        if(empty($cacheData)) {
            $orderModel = new trOrder();
            $where = Db::raw("`status` in (2,7) and reserve_time < '" . date("Y-m-d H:i:s", mktime(23, 59, 59)) . "' and reserve_time > '" . date("Y-m-d H:i:s", mktime(0, 0, 0)) . "'");
            $orderData = $orderModel->getFields("order_sn,user_id,type,address_from,reserve_time,allot_driver_id,mall_id", $where, false, false);
            if (count($orderData)) {
                $userModel = new trUser();
                foreach ($orderData as $item) {
                    $item = Tools::transferFields($item->getData());
                    request()->mallData = ["id" => $item["mallId"]]; // 重置商城ID
                    if (empty($openid[$item["userId"]])) {
                        $openid[$item["userId"]] = $userModel->getValue("openid", ["id" => $item["userId"]]);
                    }
                    $item["typeName"] = $orderModel->getAttrByType($item["type"]);
                    if ($item["type"] == "2") {
                        $tel = trSystemSet::getValue("customerServiceConfig");
                        if (empty($tel)) {
                            $tel["territoryTel"] = "";  //境内电话
                            $tel["abroadTel"] = ""; //境外电话
                        }
                        $item["memo"] = "如有疑问，请联系客服，境内电话：{$tel["territoryTel"]}，境外电话：{$tel["abroadTel"]}";
                    } else {
                        if (empty($mobile[$item["allotDriverId"]])) {
                            $driverModel = new trDriver();
                            $mobile[$item["allotDriverId"]] = $driverModel->getValue("mobile", ["id" => $item["allotDriverId"]]);
                        }
                        $item["memo"] = "如有疑问，请联系司机电话：{$mobile[$item["allotDriverId"]]}";
                    }
                    WxAppLogic::sendOrderAppointTpl($openid[$item["userId"]], $item);
                }
            }
            $endTime = mktime(23, 59, 59); //今天24点
            request()->mallData = ["id" => 0]; // 重置商城ID
            trCache::saveCache(["key" => "orderExpireJobs", "value" => "start", "time" => $endTime - time() + 21600 + 1]);
        }
        trCache::saveCache(["key" => CommonData::EXPIRE_ORDER_JAVASCRIPT, "value" => [
            "name" => CommonData::$javascriptList[CommonData::EXPIRE_ORDER_JAVASCRIPT], "aliasName" => CommonData::EXPIRE_ORDER_JAVASCRIPT,
            'execTime' => date("Y-m-d H:i:s")
        ]]);
    }

    // 支付成功后通知分配
    public function toRemindOrder($orderData){
        // 已支付单通知提醒（短信或者微信）
        $remindSetting = trSystemSet::getValue("orderRemindSetting"); // 分配提醒设置
        if(!empty($remindSetting)){
            $userModel = new trUser();
            foreach ($remindSetting as $setting){
                if($setting["status"] == "1" && !empty($setting["value"])){ // 开启推送了
                    if(strlen($setting["value"]) > 11){
                        $mobilePrefix = substr($setting["value"], 0, -11);
                        $mobile = substr($setting["value"], -11);
                    }else{
                        $mobilePrefix = "86";
                        $mobile = $setting["value"];
                    }
                    $userData = $userModel->getFields("id,openid", ["mobile" => $mobile], true, false); // 查询手机号是否是用户
//                    $result = false;
                    if(!empty($userData["id"])){ // 有用户就推送小程序模板消息
                        WxAppLogic::distributionTpl($userData["id"], $userData["openid"], $orderData);
                    }
//                    if(!$result){ // 没发模板消息或者发送失败，就发短信，暂定
                        SmsLogic::orderRemind($mobile, $mobilePrefix); // 发短信通知
//                    }
                }
            }
        }
    }

    // 取消订单
    public function cancelOrder($orderSn, $userId, $reason = '', $timer = false){
        $model = new trOrder();
        if($timer) { // 定时任务只处理未付款的单
            $filter = [["order_sn", "=", $orderSn], ["status", "=", 1]];
        }else{ // 除了已完成的单才能取消
            $filter = [["order_sn", "=", $orderSn], ["status", "not in", '8,9']];
        }
        $orderData = $model->getFields("status,type,line_id,ride_number,coupon_id,reserve_time,total_money,mobile,memo,pay_money,create_time,mall_id", $filter);
        if(!empty($orderData)) {
            $updateData["status"] = 3;
            $updateData["reason"] = $orderData["reason"] = $reason;
            if(!$model->doUpdate($updateData, ["order_sn" => $orderSn, "user_id" => $userId])) {// 取消成功
                return false;
            }
            if($orderData["status"] == '1') { // 未付款的操作
                request()->mallData = ["id" => $orderData["mallId"]]; // 重置商城ID
                // 固定线路要加车票数
                if ($orderData["type"] == "2") { // 1机场接送，2巴士路线，3专车接送，4包车线路
                    $lineModel = new trBusesLine();
                    $chooseTime = explode(" ", $orderData["reserveTime"]);
                    $classesData = $lineModel->getClassesCache($orderData["lineId"], $chooseTime[0]); // 班次数据
                    $classesData = Tools::array_replace($classesData, "shift");
                    if (isset($classesData[$chooseTime[1]])) { // 有当前的班次 , 单未付款
                        $classesData[$chooseTime[1]]["standbyTicket"] = intval($classesData[$chooseTime[1]]["standbyTicket"]) + intval($orderData["rideNumber"]);
                        $classesData[$chooseTime[1]]["deferTicket"] = intval($classesData[$chooseTime[1]]["deferTicket"]) - intval($orderData["rideNumber"]);
                        $lineModel->toSaveClassesCacheByOrder($orderData["lineId"], $chooseTime[0], array_values($classesData)); // 更新班次数据
                    }
                }
                if ($timer && $orderData["reserveTime"] > date("Y-m-d H:i:s")) {
                    SmsLogic::orderCancel($orderSn, $orderData); // 取消订单短信通知
                }
                $userModel = new trUser();
                $openid = $userModel->getValue("openid", ["id" => $userId]);
                $orderData["userId"] = $userId;
                $orderData["orderSn"] = $orderSn;
                WxAppLogic::sendOrderCancelTpl($openid, $orderData);
            }elseif($orderData["reserveTime"] > date("Y-m-d H:i:s")){ // 订单的发车时间未过 的操作
                $id = commonModel::toAdd(refundTable, [
                    "user_id" => $userId, "order_sn" => $orderSn, "type" => $orderData["type"], "money" => 0, "status" => 1,
                    "ip" => Tools::get_client_ip(), "create_time" => time(), "mall_id" => $orderData["mallId"]
                ], true);
                $statusData = trSystemSet::getValue("orderRefundVerifyStatus");
                if(isset($statusData["status"]) && $statusData["status"] == '0'){ // 自动退款
                    $fee = $this->orderRefundFee($orderData["totalMoney"], $orderData["reserveTime"]);
                    return $this->backRefundOrder($orderData["payMoney"] - $fee > 0 ? $orderData["payMoney"] - $fee : 0, ["reason" => "自动退款"], ["orderSn" => $orderSn, "id" => $id, "fee" => $fee]);
                }else{
                    $model->doUpdate(["status" => 10], ["order_sn" => $orderSn]); // 订单改成退款待审核中
                }
            }
            return true;
        }
        return true;
    }

    // 获取订单退款需要扣的手续费
    public function orderRefundFee($payMoney, $reserveTime){
        $ruleData = trSystemSet::getValue("orderCancelFeeRule");
        if(!empty($ruleData) && is_array($ruleData)){
            $ruleData = Tools::array_sort($ruleData, "time", "SORT_ASC");
            $reserveTime = !is_numeric($reserveTime) ? strtotime($reserveTime) : $reserveTime;
            foreach ($ruleData as $rule){
                if($reserveTime - ($rule["time"] * 12 * 5 * 60) <= time()) { // 成立了
                    return number_format($payMoney * $rule["percentage"] / 100, 2, '.', '');
                }
            }
        }
        return 0;
    }

    // 退款 订单退款
    public function backRefundOrder($money, $update, $data){
        $orderModel = new trOrder();
        $orderData = $orderModel->getFields("user_id,line_id,mobile,payment_no,ride_number,pay_money,type,status,reserve_time,trade_no", ["order_sn" => $data["orderSn"]], true, false);
        if (empty($orderData["tradeNo"])) {
            return ErrorCode::code("customized", "该订单未付款");
        }
        if ($orderData["status"] == "9") {
            return ErrorCode::code("customized", "该订单已经退款了");
        }
        if($money) {
            if ($money > $orderData["payMoney"]) {
                return ErrorCode::code("customized", "退款金额不能大于订单支付金额{$orderData["payMoney"]}");
            }
            $refundData = ["outRefundNo" => date('YmdHis') . rand(1000, 9999), "totalMoney" => $orderData["payMoney"], "refundFee" => $money, "outTradeNo" => $orderData["paymentNo"]];
            $wx = new WxPay();
            $result = $wx->doRefund($refundData);
            if (isset($result["code"])) {
                $returnData = ErrorCode::code("fail");
                $returnData["msg"] = "微信返回：" . $result["msg"];
                return $returnData;
            }
        }else {
            $refundData = ["outRefundNo" => date('YmdHis') . rand(1000, 9999)];
            $result["out_trade_no"] = NULL;
            $money = 0;
        }
        $refundFee = isset($data["fee"]) ? $data["fee"] : 0;
        commonModel::toUpdate(refundTable, [
            "refund_sn" => $refundData["outRefundNo"], "money" => $money, "refund_fee" => $refundFee, "status" => 2, "trade_no" => $result["out_trade_no"], "ip" => Tools::get_client_ip(), "complete_time" => time(),
        ], ["id" => $data["id"]]);
        // 固定线路要加车票数
        if ($orderData["type"] == "2") { // 1机场接送，2巴士路线，3专车接送，4包车线路
            $lineModel = new trBusesLine();
            $chooseTime = explode(" ", $orderData["reserveTime"]);
            $classesData = $lineModel->getClassesCache($orderData["lineId"], $chooseTime[0]); // 班次数据
            $classesData = Tools::array_replace($classesData, "shift");
            if (isset($classesData[$chooseTime[1]])) { // 有当前的班次
                $classesData[$chooseTime[1]]["standbyTicket"] = intval($classesData[$chooseTime[1]]["standbyTicket"]) + intval($orderData["rideNumber"]);
                $lineModel->toSaveClassesCacheByOrder($orderData["lineId"], $chooseTime[0], array_values($classesData)); // 更新班次数据
            }
        }
        $orderModel->doUpdate(["status" => 9, "reason" => $update["reason"], "refund_money" => Db::raw("refund_money+{$money}"), "refund_fee" => $refundFee], ["order_sn" => $data["orderSn"]]);
        $userModel = new trUser();//amount
        $userModel->doUpdate(["amount" => Db::raw("amount-{$money}")], ["id" => $orderData["userId"]]);
        $orderData["orderSn"] = $data["orderSn"];
        SmsLogic::orderRefund($orderData);
        $orderData["memo"] = $update["reason"];
        $orderData["typeName"] = $orderModel->getAttrByType($orderData["type"]);
        $orderData["statusText"] = $orderModel->getAttrByStatus(9);
        $openid = $userModel->getValue("openid", ["id" => $orderData["userId"]]);
        WxAppLogic::sendOrderRefundTpl($openid, $orderData);
        $returnData = ErrorCode::code("success");
        $returnData["msg"] = "退款成功";
        return $returnData;
    }
}